﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Threading;

using System.Threading.Tasks;
using System.Windows.Forms;

namespace DAQ.Common.BTSR_V1
{
    public static class BTSRSerialport
    {
        static AutoResetEvent resetEvent = new AutoResetEvent(true);

        public static AutoResetEvent ResetEvent { get => resetEvent; set => resetEvent = value; }

        public static bool SendBuffer_9bit(this SerialPort port, bool ADD, params byte[] buffer)
        {

            try
            {
                port.Parity = ADD ? Parity.Mark : Parity.Space;
                if (!port.IsOpen)
                    port.Open();
                port.Write(buffer, 0, buffer.Length);
                port.Parity = Parity.None;
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        public static bool SendCmdWithAddr(this SerialPort port, params byte[] buffer)
        {
            try
            {
                resetEvent.WaitOne();
                SendBuffer_9bit(port, true, buffer[0]);
                SendBuffer_9bit(port, false, BasicUtil.SubByte(buffer, 1, buffer.Length - 1));
                resetEvent.Set();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public static byte[] Request(this SerialPort port, byte[] buffer, int len, int timeout = 100)
        {
            ResetEvent.WaitOne();
            SendBuffer_9bit(port, true, buffer[0]);
            SendBuffer_9bit(port, false, BasicUtil.SubByte(buffer, 1, buffer.Length - 1));
            byte[] recv = port.Read(len, timeout);
            ResetEvent.Set();
            return recv;
        }
        public static byte[] Request_v2(this SerialPort port, byte[] buffer, int len, int timeout = 100)
        {
            byte[] recData = null;
            List<byte> bytes = new List<byte>();
            bool ctn = true;
            ResetEvent.WaitOne();
            if (port.IsOpen)
                port.DiscardInBuffer();
            var task0 = Task.Factory.StartNew(() =>
            {
                while (ctn)
                {
                    SendBuffer_9bit(port, true, buffer[0]);
                    SendBuffer_9bit(port, false, BasicUtil.SubByte(buffer, 1, buffer.Length - 1));
                    System.Threading.Thread.Sleep(10);
                }
            });
            var task1 = Task.Factory.StartNew(() =>
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                bool rec_ok = false;
                while (!rec_ok&&sw.ElapsedMilliseconds<timeout)
                {
                    while (port.BytesToRead > 0)
                    {
                        var rb = port.ReadByte();
                        if (rb != -1)
                            bytes.Add((byte)rb);
                        else
                            break;
                    }

                    if (bytes.Count > len)
                    {
                        recData = bytes.ToArray().SubByte(0,len);
                        rec_ok = true;
                    }
                }
            });
            while (!task1.IsCompleted)
            {
                Application.DoEvents();
                Thread.Sleep(1);
            }
            ctn = false;
            ResetEvent.Set();
            return recData;
        }

        public static byte[] Read(this SerialPort port, int len, int timeout = 500)
        {
            byte[] recData = null;
            List<byte> bytes = new List<byte>();

            if (!Wait.WithCondition(() =>
            {

                while (port.BytesToRead > 0)
                {
                    var rb = port.ReadByte();
                    if (rb != -1)
                        bytes.Add((byte)rb);
                    else
                        break;
                }
                if (bytes.Count > 0)
                {
                    if (bytes.Count == len)
                    {
                        recData = bytes.ToArray();
                        return true;
                    }
                    else
                    { return false; }
                }
                else
                { return false; }
            }, timeout))
            {
                return null;
            }
            return recData;
        }
    }
}
namespace DAQ.Common.BTSR_V2
{
    public static class BTSRSerialport
    {
        static AutoResetEvent resetEvent = new AutoResetEvent(true);

        public static AutoResetEvent ResetEvent { get => resetEvent; set => resetEvent = value; }

        public static bool SendBuffer_9bit(this SerialPort port, bool ADD, params byte[] buffer)
        {
            bool ret = false;
            try
            {

                byte[] temp = new byte[buffer.Length * 2];
                for (int i = 0; i < buffer.Length; i++)
                {
                    temp[2 * i] = (byte)(ADD ? 0xAA : 0x55);
                    temp[2 * i + 1] = buffer[i];
                }
                if (!port.IsOpen)
                    port.Open();
                port.Write(temp, 0, temp.Length);
                port.Parity = Parity.None;
                ret = true;
            }
            catch (Exception ex)
            {
                ret = false;
            }
            return ret;
        }
        public static bool SendCmdWithAddr(this SerialPort port, params byte[] buffer)
        {
            try
            {
                SendBuffer_9bit(port, true, buffer[0]);
                SendBuffer_9bit(port, false, BasicUtil.SubByte(buffer, 1, buffer.Length - 1));
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public static byte[] Request(this SerialPort port, int timeout, params byte[] buffer)
        {
            port.SendCmdWithAddr(buffer);
            byte[] recv = port.Read(timeout);
            return recv;
        }

        public static byte[] Read(this SerialPort port, int timeout = 500)
        {
            resetEvent.WaitOne();
            byte[] recData = null;
            if (Wait.WithCondition(() => { return port.BytesToRead > 0; }, timeout))
            {
                Thread.Sleep(500); //50毫秒内数据接收完毕，可根据实际情况调整
                recData = new byte[port.BytesToRead];
                port.Read(recData, 0, recData.Length);
            }
            resetEvent.Set();
            return recData;
        }
    }
}
